package com.jgp.third.wx;

import com.jgp.common.utils.JGPUtil;
import com.jgp.sys.utils.SpringContextUtil;
import com.jgp.third.wx.assist.AccessToken;
import com.jgp.third.wx.assist.JsApiTicket;
import com.jgp.third.wx.assist.RunTimeConfig;
import com.jgp.third.wx.model.WxConfig;
import com.jgp.third.wx.model.WxUseFor;
import com.jgp.third.wx.model.WxUserInfo;
import com.jgp.third.wx.service.WxService;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 项目   jgp-cloud-parent
 * 作者   loufei
 * 时间   2018/6/2
 */
public class JGPWxUtil {

    public static final String AUTH_STATIC = "snsapi_base";
    public static final String AUTH_NO_STATIC = "snsapi_userinfo";
    private static Logger logger = LoggerFactory.getLogger(JGPWxUtil.class);
    private static RunTimeConfig runTimeConfig = RunTimeConfig.getInstance();

    public static Map jsConfig(String url, String useForId) {
        WxConfig config = JGPWxUtil.getConfig(useForId);
        //创建有序的Map用于创建签名串
        SortedMap<String, Object> params = new TreeMap<>();
        //获取ticket
        String jsApiTicket = getJsApiTicket(useForId).getTicket();
        //获取Unix时间戳(java时间戳为13位,所以要截取最后3位,保留前10位)
        String timeStamp = String.valueOf(System.currentTimeMillis()).substring(0, 10);
        params.put("jsapi_ticket", jsApiTicket);
        params.put("timestamp", timeStamp);
        params.put("noncestr", JGPUtil.random());
        params.put("url", url);
        //签名
        String originStr = params.toString();
        originStr = originStr.substring(1, originStr.length() - 1).replace(" ", "").replace(",", "&");
        String signature = DigestUtils.sha1Hex(originStr);
        //得到签名再组装到Map里
        params.put("signature", signature);
        //传入对应的appId
        params.put("appId", config.getAppId());

        WxService wxService = SpringContextUtil.getBean(WxService.class);
        WxUseFor useFor = wxService.queryUseForById(Long.parseLong(useForId));
        Map<String, Object> map = new HashMap<>();
        map.put("title", useFor.getShareTitle());
        map.put("link", useFor.getShareLink());
        map.put("image", useFor.getShareImage());
        map.put("desc", useFor.getShareDesc());
        map.put("type", useFor.getShareType());
        map.put("dataUrl", useFor.getShareDataUrl());
        params.put("shareConfig", map);

        //组装完毕，回传
        return params;
    }

    public static JsApiTicket getJsApiTicket(String useForId) {
        WxConfig config = getConfig(useForId);
        JsApiTicket jsApiTicket = runTimeConfig.getJsApiTicket(config.getAppId());
        if (Objects.isNull(jsApiTicket) || JGPUtil.isTimeOut(jsApiTicket.getFromTime(), jsApiTicket
                .getExpiresIn())) {
            AccessToken token = getAccessToken(useForId);
            String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?" +
                    "access_token={token}&type=jsapi";
            Map<String, String> params = new HashMap<>();
            params.put("token", token.getAccessToken());
            RestTemplate restTemplate = SpringContextUtil.getBean(RestTemplate.class);
            Map<String, Object> map = restTemplate.getForObject(url, Map.class, params);
            jsApiTicket = new JsApiTicket();
            jsApiTicket.setTicket(map.get("ticket").toString());
            jsApiTicket.setExpiresIn(Objects.nonNull(map.get("expires_in")) ? new Integer(map.get
                    ("expires_in").toString()) : 0);
            jsApiTicket.setFromTime(LocalDateTime.now());
            runTimeConfig.addJsApiTicket(config.getAppId(), jsApiTicket);
        }

        return jsApiTicket;
    }


    public static AccessToken getAccessToken(String useForId) {
        WxConfig config = getConfig(useForId);
        AccessToken token = runTimeConfig.getAccessToken(config.getAppId());
        if (Objects.isNull(token) || JGPUtil.isTimeOut(token.getFromTime(), token.getExpiresIn())) {
            String url = "https://api.weixin.qq.com/cgi-bin/token?" +
                    "grant_type=client_credential&appid={appId}&secret={appSecret}";
            Map<String, String> params = new HashMap<>();
            params.put("appId", config.getAppId());
            params.put("appSecret", config.getAppSecret());
            RestTemplate restTemplate = SpringContextUtil.getBean(RestTemplate.class);
            Map<String, Object> map = restTemplate.getForObject(url, Map.class, params);
            token = new AccessToken();
            token.setAccessToken(map.get("access_token").toString());
            token.setExpiresIn(Objects.nonNull(map.get("expires_in")) ? new Integer(map.get("expires_in")
                    .toString()) : 0);
            token.setFromTime(LocalDateTime.now());
            runTimeConfig.addAccessToken(config.getAppId(), token);
        }
        return token;
    }


    public static WxConfig getConfig(String useForId) {
        WxService wxService = SpringContextUtil.getBean(WxService.class);
        WxUseFor useFor = wxService.queryUseForById(Long.parseLong(useForId));
        WxConfig config = runTimeConfig.getConfig(useFor.getConfigId());
        if (Objects.isNull(config)) {
            config = wxService.queryConfigByForId(Long.parseLong(useForId));
            runTimeConfig.addConfig(config);
        }
        return config;
    }

    /**
     * 获取认证连接
     *
     * @param appId
     * @param authBackUrl
     * @return
     */
    public static String getAuthRedirectUrl(String appId, String authBackUrl, String scope, String useForId,String bizId) {
        return "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appId + "&redirect_uri=" +
                authBackUrl + "&response_type=code&scope=" + scope + "&state" + "=" + useForId+","+bizId +
                "#wechat_redirect";
    }


    /**
     * 获取OPENID 及其他信息
     *
     * @param code
     * @return
     */
    public static WxUserInfo getUserInfoFromWxServer(String code, String useForId) {
        WxConfig config = getConfig(useForId);
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token" +
                "?appid={appId}&secret={appSecret}&code={code}&grant_type=authorization_code";
        Map<String, String> params = new HashMap<>();
        params.put("appId", config.getAppId());
        params.put("appSecret", config.getAppSecret());
        params.put("code", code);
        RestTemplate restTemplate = SpringContextUtil.getBean(RestTemplate.class);
        Map<String, Object> map = restTemplate.getForObject(url, Map.class, params);
        String openId = map.get("openid").toString();
        WxService wxService = SpringContextUtil.getBean(WxService.class);
        WxUserInfo userInfo = wxService.queryUserByOpenIdAndAppId(openId,config.getAppId());

        if(Objects.isNull(userInfo)){
            userInfo = new WxUserInfo();
        }

        userInfo.setOpenId(openId);
        userInfo.setAccessToken(map.get("access_token").toString());
        userInfo.setExpiresIn(Objects.nonNull(map.get("expires_in")) ? new Integer(map.get("expires_in")
                .toString()) : 0);
        userInfo.setRefreshToken(map.get("refresh_token").toString());
        userInfo.setAppId(config.getAppId());
        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
                "?access_token={accessToken}&openid={openId}&lang=zh_CN";
        Map<String, String> params2 = new HashMap<>();
        params2.put("accessToken", userInfo.getAccessToken());
        params2.put("openId", userInfo.getOpenId());
        Map<String, Object> map2 = restTemplate.getForObject(userInfoUrl, Map.class, params2);
        userInfo.setProvince(map2.get("province").toString());
        userInfo.setCity(map2.get("city").toString());
        userInfo.setCountry(map2.get("country").toString());
        userInfo.setSex(map2.get("sex").toString());
        userInfo.setHeadImageUrl(map2.get("headimgurl").toString());
        userInfo.setUnionId(Objects.nonNull(map2.get("unionid")) ? map2.get("unionid").toString() : null);

        wxService.saveWxUser(userInfo);

        return userInfo;
    }

    public static WxUserInfo getUserInfoByOpenIdAndAppId(String openId, String appId) {
        WxService wxService = SpringContextUtil.getBean(WxService.class);
        return wxService.queryUserByOpenIdAndAppId(openId, appId);
    }
}
